import { Op } from 'sequelize';
import Category from '../models/Category';
import Article from '../models/Article';
import { redisClient } from '../database';

// 分类查询参数接口
interface CategoryQueryParams {
  parent_id?: string | null;
  keyword?: string;
  include_article_count?: boolean;
  sort_by?: string;
  sort_order?: 'ASC' | 'DESC';
  status?: 'active' | 'inactive';
}

// 分类创建接口
interface CategoryCreateParams {
  name: string;
  slug: string;
  description?: string;
  parent_id?: string | null;
  order?: number;
  status?: 'active' | 'inactive';
}

// 分类更新接口
interface CategoryUpdateParams extends Partial<CategoryCreateParams> {}

class CategoryService {
  /**
   * 获取分类列表
   * @param params 查询参数
   * @returns 分类列表
   */
  async getCategories(params: CategoryQueryParams = {}) {
    const {
      parent_id,
      keyword,
      include_article_count = false,
      sort_by = 'order',
      sort_order = 'ASC',
      status,
    } = params;
    
    // 构建查询条件
    const where: any = {};
    
    if (parent_id !== undefined) {
      where.parent_id = parent_id;
    }
    
    if (keyword) {
      where[Op.or] = [
        { name: { [Op.like]: `%${keyword}%` } },
        { slug: { [Op.like]: `%${keyword}%` } },
        { description: { [Op.like]: `%${keyword}%` } },
      ];
    }
    
    if (status) {
      where.status = status;
    }
    
    // 执行查询
    const categories = await Category.findAll({
      where,
      order: [[sort_by, sort_order]],
      include: include_article_count ? [
        {
          model: Article,
          as: 'articles',
          attributes: ['id'],
          where: { status: 'published' },
          required: false,
        }
      ] : [],
    });
    
    // 转换为树形结构（如果未指定parent_id）
    if (parent_id === undefined) {
      return this.buildCategoryTree(categories);
    }
    
    return categories;
  }
  
  /**
   * 构建分类树形结构
   * @param categories 分类列表
   * @param parentId 父分类ID
   * @returns 树形结构的分类列表
   */
  private buildCategoryTree(categories: any[], parentId: string | null = null) {
    const result: any[] = [];
    
    categories.forEach(category => {
      if (category.parent_id === parentId) {
        const children = this.buildCategoryTree(categories, category.id);
        if (children.length > 0) {
          category.setDataValue('children', children);
        }
        result.push(category);
      }
    });
    
    return result;
  }
  
  /**
   * 根据ID获取分类详情
   * @param id 分类ID
   * @returns 分类详情
   */
  async getCategoryById(id: string) {
    // 先尝试从缓存获取
    const cacheKey = `category:${id}`;
    const cachedCategory = await redisClient.get(cacheKey);
    
    if (cachedCategory) {
      return JSON.parse(cachedCategory);
    }
    
    // 缓存未命中，从数据库获取
    const category = await Category.findByPk(id, {
      include: [
        {
          model: Category,
          as: 'parent',
          attributes: ['id', 'name', 'slug'],
        },
        {
          model: Category,
          as: 'children',
          attributes: ['id', 'name', 'slug', 'order'],
        },
      ],
    });
    
    if (!category) {
      throw new Error('分类不存在');
    }
    
    // 缓存分类
    await redisClient.set(cacheKey, JSON.stringify(category), {
      EX: 3600, // 缓存1小时
    });
    
    return category;
  }
  
  /**
   * 创建分类
   * @param params 分类参数
   * @returns 创建的分类
   */
  async createCategory(params: CategoryCreateParams) {
    const {
      name,
      slug,
      description,
      parent_id,
      order,
      status = 'active',
    } = params;
    
    // 检查slug是否已存在
    const existingCategory = await Category.findOne({
      where: { slug },
    });
    
    if (existingCategory) {
      throw new Error('分类slug已存在，请修改后重试');
    }
    
    // 如果有父分类，检查其是否存在
    if (parent_id) {
      const parentCategory = await Category.findByPk(parent_id);
      if (!parentCategory) {
        throw new Error('父分类不存在');
      }
    }
    
    // 创建分类
    const category = await Category.create({
      name,
      slug,
      description,
      parent_id,
      order: order || await this.getNextOrder(parent_id),
      status,
    });
    
    return category;
  }
  
  /**
   * 获取下一个排序值
   * @param parentId 父分类ID
   * @returns 下一个排序值
   */
  private async getNextOrder(parentId: string | null = null) {
    const maxOrderCategory = await Category.findOne({
      where: { parent_id: parentId },
      order: [['order', 'DESC']],
    });
    
    return maxOrderCategory ? maxOrderCategory.order + 10 : 10;
  }
  
  /**
   * 更新分类
   * @param id 分类ID
   * @param params 更新参数
   * @returns 更新后的分类
   */
  async updateCategory(id: string, params: CategoryUpdateParams) {
    const category = await Category.findByPk(id);
    
    if (!category) {
      throw new Error('分类不存在');
    }
    
    const {
      name,
      slug,
      description,
      parent_id,
      order,
      status,
    } = params;
    
    // 检查slug是否已被其他分类使用
    if (slug && slug !== category.slug) {
      const existingCategory = await Category.findOne({
        where: {
          slug,
          id: { [Op.ne]: id },
        },
      });
      
      if (existingCategory) {
        throw new Error('分类slug已存在，请修改后重试');
      }
    }
    
    // 不允许将分类的父级设置为自己或其子分类
    if (parent_id && parent_id !== category.parent_id) {
      if (parent_id === id) {
        throw new Error('不能将分类的父级设置为自己');
      }
      
      // 检查是否设置为自己的子分类
      const childCategories = await this.getAllChildrenIds(id);
      if (childCategories.includes(parent_id)) {
        throw new Error('不能将分类的父级设置为其子分类');
      }
      
      // 检查父分类是否存在
      const parentCategory = await Category.findByPk(parent_id);
      if (!parentCategory) {
        throw new Error('父分类不存在');
      }
    }
    
    // 准备更新数据
    const updateData: any = {};
    
    if (name !== undefined) updateData.name = name;
    if (slug !== undefined) updateData.slug = slug;
    if (description !== undefined) updateData.description = description;
    if (parent_id !== undefined) updateData.parent_id = parent_id;
    if (order !== undefined) updateData.order = order;
    if (status !== undefined) updateData.status = status;
    
    // 更新分类
    await category.update(updateData);
    
    // 清除缓存
    await redisClient.del(`category:${id}`);
    
    // 重新加载分类
    const updatedCategory = await this.getCategoryById(id);
    
    return updatedCategory;
  }
  
  /**
   * 获取所有子分类ID
   * @param categoryId 分类ID
   * @returns 子分类ID数组
   */
  private async getAllChildrenIds(categoryId: string) {
    const childrenIds: string[] = [];
    
    const findChildren = async (parentId: string) => {
      const children = await Category.findAll({
        where: { parent_id: parentId },
        attributes: ['id'],
      });
      
      for (const child of children) {
        childrenIds.push(child.id);
        await findChildren(child.id);
      }
    };
    
    await findChildren(categoryId);
    
    return childrenIds;
  }
  
  /**
   * 删除分类
   * @param id 分类ID
   * @param transferToId 转移文章到指定分类ID
   * @returns 删除结果
   */
  async deleteCategory(id: string, transferToId?: string) {
    const category = await Category.findByPk(id);
    
    if (!category) {
      throw new Error('分类不存在');
    }
    
    // 检查是否有子分类
    const childCategories = await Category.findAll({
      where: { parent_id: id },
    });
    
    if (childCategories.length > 0) {
      throw new Error('该分类下有子分类，无法删除');
    }
    
    // 获取分类下的文章数量
    const articleCount = await Article.count({
      where: { category_id: id },
    });
    
    // 如果有文章且未指定转移分类，则拒绝删除
    if (articleCount > 0 && !transferToId) {
      throw new Error(`该分类下有${articleCount}篇文章，请指定转移分类后再删除`);
    }
    
    // 如果指定了转移分类，则将文章转移
    if (transferToId) {
      // 检查转移目标分类是否存在
      const targetCategory = await Category.findByPk(transferToId);
      if (!targetCategory) {
        throw new Error('转移目标分类不存在');
      }
      
      // 更新文章分类
      await Article.update(
        { category_id: transferToId },
        { where: { category_id: id } }
      );
    }
    
    // 删除分类
    await category.destroy();
    
    // 清除缓存
    await redisClient.del(`category:${id}`);
    
    return { success: true, message: '删除分类成功' };
  }
  
  /**
   * 批量更新分类排序
   * @param orderData 排序数据，格式：[{id: '1', order: 10}, {id: '2', order: 20}]
   * @returns 更新结果
   */
  async updateCategoriesOrder(orderData: Array<{id: string, order: number}>) {
    const transaction = await Category.sequelize!.transaction();
    
    try {
      for (const item of orderData) {
        await Category.update(
          { order: item.order },
          { 
            where: { id: item.id },
            transaction 
          }
        );
        
        // 清除缓存
        await redisClient.del(`category:${item.id}`);
      }
      
      await transaction.commit();
      
      return { success: true, message: '更新分类排序成功' };
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }
}

export default new CategoryService(); 